package com.liu.qqRobot.wm.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.liu.common.utils.HtmlToImageUtils;
import com.liu.common.utils.QQClientUtils;
import com.liu.common.utils.WmClientUtils;
import com.liu.mybatisPlus.wm.entity.base.WmRivenAttributes;
import com.liu.mybatisPlus.wm.entity.base.WmRivenItem;
import com.liu.mybatisPlus.wm.entity.base.WmRivenListen;
import com.liu.mybatisPlus.wm.service.WmRivenAttributesService;
import com.liu.mybatisPlus.wm.service.WmRivenItemService;
import com.liu.mybatisPlus.wm.service.WmRivenListenService;
import com.liu.qqRobot.wm.entity.dto.WarframeMarketRivenAuctionDTO;
import com.liu.qqRobot.wm.entity.dto.WarframeMarketRivenAuctionTemplateDTO;
import com.liu.qqRobot.wm.enums.AuctionsSortByEnum;
import com.liu.qqRobot.wm.service.WmrlService;
import freemarker.template.TemplateException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WmrlServiceImpl implements WmrlService {

    @Resource
    private WmRivenListenService wmRivenListenService;

    @Resource
    private WmRivenItemService wmRivenItemService;

    @Resource
    private WmRivenAttributesService wmRivenAttributesService;

    @Override
    public void listening() {
        Integer page = 1;
        QueryWrapper<WmRivenListen> wmRivenListenQueryWrapper = new QueryWrapper<>();
        wmRivenListenQueryWrapper.eq("is_delete", false);
        List<WmRivenListen> wmRivenListens = wmRivenListenService.list(wmRivenListenQueryWrapper);
        List<WmRivenListen> updateList = new ArrayList<>();
        wmRivenListens.forEach(wmRivenListen -> {
            updateList.add(wmRivenListen);
            wmRivenListen.setQuantity(wmRivenListen.getQuantity() == null?0:wmRivenListen.getQuantity() + 1);
            Long groupId = wmRivenListen.getGroupId();
            Long userId = wmRivenListen.getUserId();
            Boolean isGroup = wmRivenListen.getIsGroup();
            Map<String, Object> param = this.getParam(wmRivenListen.getParam(), groupId, userId, isGroup);
            String rivenName = (String) param.get("rivenName");
            if (StrUtil.isNotEmpty(rivenName)) {
                QueryWrapper<WmRivenItem> wmRivenItemQueryWrapper = new QueryWrapper<>();
                wmRivenItemQueryWrapper.like("item_name", param.get("rivenName"));
                List<WmRivenItem> wmRivenItemList = wmRivenItemService.list(wmRivenItemQueryWrapper);
                if (wmRivenItemList.size() == 1) {
                    WmRivenItem wmRivenItem = wmRivenItemList.get(0);
                    this.queryAndSend(wmRivenItem, param, groupId, userId, page, isGroup);
                    return;
                }
                wmRivenListen.setIsDelete(true);
                if (wmRivenItemList.size() > 1) {
                    StringBuilder msg = new StringBuilder("[CQ:at,qq=" + userId + "]\n以下有多个匹配的结果，请确认你要查询的物品：\n");
                    for (WmRivenItem wmRivenItem : wmRivenItemList) {
                        msg.append("【").append(wmRivenItem.getItemName()).append("】  ");
                    }
                    msg.append("\n当前指令任务已经作废，请重新创建任务");
                    QQClientUtils.sendMsg(msg.toString(), userId, groupId, isGroup);
                } else {
                    QQClientUtils.sendMsg("[CQ:at,qq=" + userId + "]\n无法找到你想要查询的物品，请确认名称是否准确\n当前指令任务已经作废，请重新创建任务", userId, groupId, isGroup);
                }
            } else {
                this.queryAndSend(null, param, groupId, userId, page, isGroup);
            }
        });
        wmRivenListenService.updateBatchById(updateList);
    }

    private void queryAndSend(WmRivenItem wmRivenItem, Map<String, Object> param, Long groupId, Long userId, Integer page, Boolean isGroup) {
        List<String> positiveStatsList = (List<String>) param.getOrDefault("positiveStatsList", null);
        String positiveStats = null;
        if (CollUtil.isNotEmpty(positiveStatsList)) {
            QueryWrapper<WmRivenAttributes> wmRivenAttributesQueryWrapper = new QueryWrapper<>();
            wmRivenAttributesQueryWrapper.in("effect", positiveStatsList);
            List<WmRivenAttributes> wmRivenAttributesList = wmRivenAttributesService.list(wmRivenAttributesQueryWrapper);
            List<String> rivenAttributesUrlNameList = wmRivenAttributesList.stream().map(WmRivenAttributes::getUrlName).collect(Collectors.toList());
            positiveStats = CollUtil.join(rivenAttributesUrlNameList, ",");
        }
        List<String> negativeStatsList = (List<String>) param.getOrDefault("negativeStatsList", null);
        String negativeStats = null;
        if (CollUtil.isNotEmpty(negativeStatsList)) {
            QueryWrapper<WmRivenAttributes> wmRivenAttributesQueryWrapper = new QueryWrapper<>();
            wmRivenAttributesQueryWrapper.in("effect", negativeStatsList);
            List<WmRivenAttributes> wmRivenAttributesList = wmRivenAttributesService.list(wmRivenAttributesQueryWrapper);
            List<String> rivenAttributesUrlNameList = wmRivenAttributesList.stream().map(WmRivenAttributes::getUrlName).collect(Collectors.toList());
            negativeStats = CollUtil.join(rivenAttributesUrlNameList, ",");
        }
        List<WarframeMarketRivenAuctionDTO> warframeMarketRivenAuctionDTOList = WmClientUtils.getRivenAuctions("riven", "direct",
                wmRivenItem == null ? null:wmRivenItem.getUrlName(), positiveStats,
                negativeStats, null, null, null, null, null, null, null, AuctionsSortByEnum.PRICE_ASC.getType());
        // 判断价格条件
        Integer price = (Integer) param.get("price");
        if (price != null) {
            warframeMarketRivenAuctionDTOList = warframeMarketRivenAuctionDTOList.stream()
                    .filter(w -> {
                        if (w.getBuyoutPrice() != null) {
                            return w.getBuyoutPrice() <= price;
                        } else if (w.getTopBid() != null){
                            return w.getTopBid() <= price;
                        } else {
                            return w.getStartingPrice() <= price;
                        }
                    }).filter(w -> Arrays.asList("ingame", "online").contains(w.getOwner().getStatus())).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(warframeMarketRivenAuctionDTOList)) {
//                    QQClientUtils.sendGroupMsg("[CQ:at,qq=" + userId + "]\n目前没有找到符合指令：" + wmRivenListen.getParam() + "的紫卡拍卖", groupId);
            return;
        }
        // 判断排序
        warframeMarketRivenAuctionDTOList.forEach(warframeMarketItemsOrderDTO -> {
            warframeMarketItemsOrderDTO.setSort(this.getSortByStatus(warframeMarketItemsOrderDTO.getOwner().getStatus()));
        });
        // 排序 ingame-1 online-2 offline-3，后排序价格
        warframeMarketRivenAuctionDTOList = warframeMarketRivenAuctionDTOList.stream()
                .sorted(Comparator.comparing(WarframeMarketRivenAuctionDTO::getSort).thenComparing(WarframeMarketRivenAuctionDTO::getStartingPrice))
                .collect(Collectors.toList());
        List<List<WarframeMarketRivenAuctionDTO>> warframeMarketRivenAuctionDTOListSplit = ListUtil.split(warframeMarketRivenAuctionDTOList, 5);
        List<WarframeMarketRivenAuctionTemplateDTO> warframeMarketRivenAuctionTemplateDTOList = new ArrayList<>();
        for (int i = 0; i < warframeMarketRivenAuctionDTOListSplit.size(); i++) {
            List<WarframeMarketRivenAuctionDTO> warframeMarketRivenAuctionDTOS = warframeMarketRivenAuctionDTOListSplit.get(page - 1);
            List<String> weaponUrlNameList = warframeMarketRivenAuctionDTOS.stream().map(w -> w.getItem().getWeaponUrlName()).distinct().collect(Collectors.toList());
            QueryWrapper<WmRivenItem> wmRivenItemQueryWrapper = new QueryWrapper<>();
            wmRivenItemQueryWrapper.in("url_name", weaponUrlNameList);
            List<WmRivenItem> wmRivenItemList = wmRivenItemService.list(wmRivenItemQueryWrapper);
            Map<String, String> itemNameMap = wmRivenItemList.stream().collect(Collectors.toMap(WmRivenItem::getUrlName, WmRivenItem::getItemName));
            for (int i1 = 0; i1 < warframeMarketRivenAuctionDTOS.size(); i1++) {
                WarframeMarketRivenAuctionDTO warframeMarketRivenAuctionDTO = warframeMarketRivenAuctionDTOS.get(i1);
                WarframeMarketRivenAuctionTemplateDTO warframeMarketRivenAuctionTemplateDTO = new WarframeMarketRivenAuctionTemplateDTO();
                warframeMarketRivenAuctionTemplateDTO.setStartingPrice(String.valueOf(warframeMarketRivenAuctionDTO.getStartingPrice()));
                warframeMarketRivenAuctionTemplateDTO.setBuyoutPrice(String.valueOf(warframeMarketRivenAuctionDTO.getBuyoutPrice()));
                warframeMarketRivenAuctionTemplateDTO.setTopBid(warframeMarketRivenAuctionDTO.getTopBid() == null ? "暂无":String.valueOf(warframeMarketRivenAuctionDTO.getTopBid()));
                warframeMarketRivenAuctionTemplateDTO.setIngameName(warframeMarketRivenAuctionDTO.getOwner().getIngameName());
                warframeMarketRivenAuctionTemplateDTO.setStatus(this.getStatusDesc(warframeMarketRivenAuctionDTO.getOwner().getStatus()));
                warframeMarketRivenAuctionTemplateDTO.setModRank(String.valueOf(warframeMarketRivenAuctionDTO.getItem().getModRank()));
                warframeMarketRivenAuctionTemplateDTO.setMasteryLevel(String.valueOf(warframeMarketRivenAuctionDTO.getItem().getMasteryLevel()));
                warframeMarketRivenAuctionTemplateDTO.setReRolls(String.valueOf(warframeMarketRivenAuctionDTO.getItem().getReRolls()));
                warframeMarketRivenAuctionTemplateDTO.setPolarity(warframeMarketRivenAuctionDTO.getItem().getPolarity());
                warframeMarketRivenAuctionTemplateDTO.setItemName(itemNameMap.getOrDefault(warframeMarketRivenAuctionDTO.getItem().getWeaponUrlName(), "") + " " + warframeMarketRivenAuctionDTO.getItem().getName());

                List<WarframeMarketRivenAuctionDTO.Item.Attribute> modPositiveStatsList = warframeMarketRivenAuctionDTO.getItem().getAttributes().stream().filter(WarframeMarketRivenAuctionDTO.Item.Attribute::getPositive).toList();
                List<WarframeMarketRivenAuctionDTO.Item.Attribute> modNegativeStatsList = warframeMarketRivenAuctionDTO.getItem().getAttributes().stream().filter(a -> !a.getPositive()).toList();
                List<String> attributeUrlNameList = warframeMarketRivenAuctionDTO.getItem().getAttributes().stream().map(WarframeMarketRivenAuctionDTO.Item.Attribute::getUrlName).collect(Collectors.toList());
                QueryWrapper<WmRivenAttributes> wmRivenAttributesQueryWrapper = new QueryWrapper<>();
                wmRivenAttributesQueryWrapper.in("url_name", attributeUrlNameList);
                List<WmRivenAttributes> wmRivenAttributesList = wmRivenAttributesService.list(wmRivenAttributesQueryWrapper);
                Map<String, WmRivenAttributes> wmRivenAttributesMap = wmRivenAttributesList.stream().collect(Collectors.toMap(WmRivenAttributes::getUrlName, a -> a));
                StringBuilder modPositiveStats = new StringBuilder();
                for (WarframeMarketRivenAuctionDTO.Item.Attribute attribute : modPositiveStatsList) {
                    WmRivenAttributes attributes = wmRivenAttributesMap.get(attribute.getUrlName());
                    modPositiveStats.append("+").append(attributes.getEffect()).append(this.getUnitValue(attributes.getUnits(), attribute.getValue())).append(" | ");
                }
                warframeMarketRivenAuctionTemplateDTO.setPositiveStats(modPositiveStats.toString());
                StringBuilder modNegativeStats = new StringBuilder();
                for (WarframeMarketRivenAuctionDTO.Item.Attribute attribute : modNegativeStatsList) {
                    WmRivenAttributes attributes = wmRivenAttributesMap.get(attribute.getUrlName());
                    modNegativeStats.append("-").append(attributes.getEffect()).append(this.getUnitValue(attributes.getUnits(), attribute.getValue())).append(" | ");
                }
                warframeMarketRivenAuctionTemplateDTO.setNegativeStats(StrUtil.isEmpty(modNegativeStats.toString())?null:modNegativeStats.toString());
                warframeMarketRivenAuctionTemplateDTOList.add(warframeMarketRivenAuctionTemplateDTO);
            }
            break;
        }
        Map<String, Object> templateParam = new HashMap<>();
        templateParam.put("param", param.get("rivenName"));
        templateParam.put("itemName", wmRivenItem == null ? "":wmRivenItem.getItemName());
        templateParam.put("auctionList", warframeMarketRivenAuctionTemplateDTOList);
        try {
            HtmlToImageUtils.htmlToImage("rivenAuctionTemplate.html", templateParam, "src/main/resources/picture/rivenAuction.png", 2600);
            File file = new File("src/main/resources/picture/rivenAuction.png");
            String encode = Base64.encode(file);
            String msg = "[CQ:at,qq=" + userId + "]\n[CQ:image,file=base64://" + encode+ ",type=show,subType=0]";
            QQClientUtils.sendMsg(msg, userId, groupId, isGroup);
        } catch (IOException | TemplateException | ParserConfigurationException | SAXException e) {
            log.error("获取紫卡展示模板失败:{}", e.getMessage(), e);
            QQClientUtils.sendMsg("[CQ:at,qq=" + userId + "]\n获取紫卡展示模板失败，请联系制作人", userId, groupId, isGroup);
        }
    }

    /**
     * 解析参数
     * @return Map<String, String>
     */
    private Map<String, Object> getParam(String text, Long groupId, Long userId, Boolean isGroup) {
        Map<String, Object> result = new HashMap<>();
        String[] wmlS = text.replace("wmrl ", "").split("] \\[");
        String rivenName = null;
        List<String> positiveStatsList = null;
        List<String> negativeStatsList = null;
        Integer price = null;
        for (int i = 0; i < wmlS.length; i++) {
            // 第一位是赤毒名称
            if (i == 0 && StrUtil.isNotEmpty(wmlS[i])) {
                rivenName = wmlS[i].replace("[", "").replace("]", "");
            }
            // 第二位是正向属性
            if (i == 1 && StrUtil.isNotEmpty(wmlS[i])) {
                positiveStatsList = Arrays.asList(wmlS[i].replace("[", "").replace("]", "").split(","));
                if (positiveStatsList.size() > 3) {
                    QQClientUtils.sendMsg("[CQ:at,qq=" + userId + "]\n正面属性最多只能输入三个\n", userId, groupId, isGroup);
                }
            }
            // 第三位是反向属性
            if (i == 2 && StrUtil.isNotEmpty(wmlS[i])) {
                negativeStatsList = Arrays.asList(wmlS[i].replace("[", "").replace("]", "").split(","));
                if (negativeStatsList.size() > 3) {
                    QQClientUtils.sendMsg("[CQ:at,qq=" + userId + "]\n反面属性最多只能输入三个\n", userId, groupId, isGroup);
                }
            }
            // 第四位是价格
            if (i == 3 && StrUtil.isNotEmpty(wmlS[i])) {
                price = Integer.valueOf(wmlS[i].replace("[", "").replace("]", ""));
            }
        }
        result.put("rivenName", rivenName);
        result.put("positiveStatsList", positiveStatsList);
        result.put("negativeStatsList", negativeStatsList);
        result.put("price", price);
        return result;
    }

    /**
     * 解析状态判断排序
     * @param status offline ingame online
     * @return String
     */
    private Integer getSortByStatus(String status) {
        return switch (status) {
            case "offline" -> 3;
            case "ingame" -> 1;
            case "online" -> 2;
            default -> 4;
        };
    }

    /**
     * 解析状态为中文
     * @param status offline ingame online
     * @return String
     */
    private String getStatusDesc(String status) {
        return switch (status) {
            case "offline" -> "离线";
            case "ingame" -> "游戏中";
            case "online" -> "在线";
            default -> "";
        };
    }

    /**
     * 解析属性值单位
     * @param unit 单位
     * @return String
     */
    private String getUnitValue(String unit, BigDecimal value) {
        if (StrUtil.isEmpty(unit)) {
            return value.setScale(2, RoundingMode.HALF_UP).toString();
        } else {
            return switch (unit) {
                case "percent" -> value.setScale(2, RoundingMode.HALF_UP) + "%";
                case "multiply" -> "X" + value.setScale(2, RoundingMode.HALF_UP);
                case "seconds" -> value.setScale(2, RoundingMode.HALF_UP) + "秒";
                default -> value.setScale(2, RoundingMode.HALF_UP).toString();
            };
        }
    }
}
